const url = require('url');
const querystring = require('querystring');

/**
 * API router handles HTTP API endpoints
 */
class ApiRouter {
    constructor(roomManager) {
        this.roomManager = roomManager;
    }

    /**
     * Route API requests
     */
    async handleRequest(req, res) {
        const parsedUrl = url.parse(req.url, true);
        const pathname = parsedUrl.pathname;
        const method = req.method;

        // Set CORS headers
        res.setHeader('Access-Control-Allow-Origin', '*');
        res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
        res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization');

        // Handle preflight requests
        if (method === 'OPTIONS') {
            res.writeHead(200);
            res.end();
            return;
        }

        try {
            // Route to appropriate handler
            if (pathname === '/api/rooms' && method === 'POST') {
                await this.createRoom(req, res);
            } else if (pathname.match(/^\/api\/rooms\/[^\/]+$/) && method === 'GET') {
                await this.getRoomInfo(req, res);
            } else if (pathname.match(/^\/api\/rooms\/[^\/]+\/join$/) && method === 'POST') {
                await this.joinRoom(req, res);
            } else if (pathname.match(/^\/api\/invite\/[^\/]+$/) && method === 'GET') {
                await this.validateInvite(req, res);
            } else if (pathname === '/api/validate-session' && method === 'POST') {
                await this.validateSession(req, res);
            } else if (pathname === '/api/sessions/validate' && method === 'POST') {
                await this.validateSessionEnhanced(req, res);
            } else if (pathname === '/api/stats' && method === 'GET') {
                await this.getStats(req, res);
            } else {
                this.sendError(res, 404, 'API endpoint not found');
            }
        } catch (error) {
            console.error('API Error:', error);
            this.sendError(res, 500, 'Internal server error');
        }
    }

    /**
     * Create a new room
     * POST /api/rooms
     */
    async createRoom(req, res) {
        try {
            const body = await this.getRequestBody(req);
            const { name, password, maxUsers, creatorNickname } = body;

            if (!name) {
                return this.sendError(res, 400, 'Room name is required');
            }

            if (!creatorNickname) {
                return this.sendError(res, 400, 'Creator nickname is required');
            }

            // Create the room
            const room = this.roomManager.createRoom(name, password, maxUsers);
            
            // Auto-join the creator to the room
            const { user } = this.roomManager.joinRoom(room.id, creatorNickname, password);
            
            // Generate session token
            const sessionToken = this.generateSessionToken();
            user.sessionToken = sessionToken;
            
            const response = {
                success: true,
                userId: user.id,
                roomId: room.id,
                nickname: user.nickname,
                sessionToken: sessionToken,
                isOwner: true,
                room: room.toJSON(),
                user: user.toJSON(),
                inviteUrl: this.getInviteUrl(req, room.inviteCode),
                websocketUrl: this.getWebSocketUrl(req)
            };

            this.sendJSON(res, 201, response);
        } catch (error) {
            console.error('Create room error:', error);
            this.sendError(res, 400, error.message);
        }
    }

    /**
     * Get room information
     * GET /api/rooms/:roomId
     */
    async getRoomInfo(req, res) {
        try {
            const roomId = this.extractPathParam(req.url, 3); // /api/rooms/:roomId
            const room = this.roomManager.getRoom(roomId);

            if (!room) {
                return this.sendError(res, 404, 'Room not found');
            }

            this.sendJSON(res, 200, {
                success: true,
                room: room.toJSON()
            });
        } catch (error) {
            console.error('Get room info error:', error);
            this.sendError(res, 400, error.message);
        }
    }

    /**
     * Join a room (prepare for WebSocket connection)
     * POST /api/rooms/:roomId/join
     */
    async joinRoom(req, res) {
        try {
            const roomId = this.extractPathParam(req.url, 3); // /api/rooms/:roomId/join
            const body = await this.getRequestBody(req);
            const { nickname, password } = body;

            // Validate that the user can join (without actually joining via WebSocket)
            const room = this.roomManager.getRoom(roomId);
            if (!room) {
                return this.sendError(res, 404, 'Room not found');
            }

            if (!nickname) {
                return this.sendError(res, 400, 'Nickname is required');
            }

            if (!room.validatePassword(password)) {
                return this.sendError(res, 403, 'Invalid room password');
            }

            if (room.members.size >= room.maxUsers) {
                return this.sendError(res, 409, 'Room is full');
            }

            // Check if nickname is already taken
            const existingUser = Array.from(room.members.values())
                .find(user => user.nickname.toLowerCase() === nickname.trim().toLowerCase());
            
            if (existingUser) {
                return this.sendError(res, 409, 'Nickname is already taken in this room');
            }

            // Pre-create user and generate session token
            const { user } = this.roomManager.joinRoom(roomId, nickname, password);
            const sessionToken = this.generateSessionToken();
            user.sessionToken = sessionToken;

            this.sendJSON(res, 200, {
                success: true,
                userId: user.id,
                roomId: roomId,
                nickname: user.nickname,
                sessionToken: sessionToken,
                isOwner: false,
                room: room.toJSON(),
                user: user.toJSON(),
                websocketUrl: this.getWebSocketUrl(req)
            });
        } catch (error) {
            console.error('Join room preparation error:', error);
            this.sendError(res, 400, error.message);
        }
    }

    /**
     * Validate invite code
     * GET /api/invite/:inviteCode
     */
    async validateInvite(req, res) {
        try {
            const inviteCode = this.extractPathParam(req.url, 3); // /api/invite/:inviteCode
            const result = this.roomManager.validateInviteCode(inviteCode);

            if (!result.valid) {
                return this.sendError(res, 404, 'Invalid or expired invite code');
            }

            this.sendJSON(res, 200, {
                success: true,
                valid: true,
                room: result.room,
                websocketUrl: this.getWebSocketUrl(req)
            });
        } catch (error) {
            console.error('Validate invite error:', error);
            this.sendError(res, 400, error.message);
        }
    }

    /**
     * Validate user session
     * POST /api/validate-session
     */
    async validateSession(req, res) {
        try {
            const body = await this.getRequestBody(req);
            const { roomId, userId, sessionToken } = body;

            if (!roomId || !userId || !sessionToken) {
                return this.sendError(res, 400, 'Missing required session parameters');
            }

            // Get the room
            const room = this.roomManager.getRoom(roomId);
            if (!room) {
                return this.sendError(res, 404, 'Room not found');
            }

            // Get the user from the room
            const user = room.getUser(userId);
            if (!user) {
                return this.sendError(res, 401, 'User not found in room');
            }

            // Validate session token
            if (user.sessionToken !== sessionToken) {
                return this.sendError(res, 401, 'Invalid session token');
            }

            this.sendJSON(res, 200, {
                success: true,
                valid: true,
                user: user.toJSON(),
                room: room.toJSON()
            });
        } catch (error) {
            console.error('Validate session error:', error);
            this.sendError(res, 400, error.message);
        }
    }

    /**
     * Enhanced session validation for recovery scenarios
     * POST /api/sessions/validate
     */
    async validateSessionEnhanced(req, res) {
        try {
            const body = await this.getRequestBody(req);
            const { userId, roomId, sessionToken } = body;

            if (!roomId || !userId) {
                return this.sendError(res, 400, 'Missing required parameters: roomId and userId');
            }

            const room = this.roomManager.getRoom(roomId);
            
            if (!room) {
                return this.sendJSON(res, 200, {
                    valid: false,
                    roomExists: false,
                    reason: 'Room no longer exists'
                });
            }

            const user = this.roomManager.users.get(userId);
            
            if (!user || (sessionToken && user.sessionToken !== sessionToken)) {
                return this.sendJSON(res, 200, {
                    valid: false,
                    roomExists: true,
                    room: room.toJSON(),
                    reason: sessionToken ? 'Session expired or invalid' : 'User session not found'
                });
            }

            // Check if user is still a member of the room
            if (!room.members.has(userId)) {
                return this.sendJSON(res, 200, {
                    valid: false,
                    roomExists: true,
                    room: room.toJSON(),
                    reason: 'User no longer in room'
                });
            }

            // Session is valid - prepare detailed room data for recovery
            const roomData = {
                room: {
                    ...room.getDetailedInfo(),
                    memberCount: room.members.size,
                    users: Array.from(room.members.values()).map(u => ({
                        id: u.id,
                        nickname: u.nickname,
                        isOnline: u.isOnline,
                        joinedAt: u.joinedAt
                    }))
                },
                userSession: {
                    userId: user.id,
                    nickname: user.nickname,
                    sessionToken: user.sessionToken,
                    joinedAt: user.joinedAt,
                    isOwner: room.owner === user.id,
                    isOnline: user.isOnline
                }
            };

            this.sendJSON(res, 200, {
                valid: true,
                roomExists: true,
                roomData
            });
            
        } catch (error) {
            console.error('Enhanced session validation error:', error);
            this.sendJSON(res, 500, { 
                valid: false, 
                error: 'Server error during session validation'
            });
        }
    }

    /**
     * Get server statistics
     * GET /api/stats
     */
    async getStats(req, res) {
        try {
            const stats = this.roomManager.getStats();
            this.sendJSON(res, 200, {
                success: true,
                stats
            });
        } catch (error) {
            console.error('Get stats error:', error);
            this.sendError(res, 500, 'Failed to get statistics');
        }
    }

    /**
     * Get request body as JSON
     */
    async getRequestBody(req) {
        return new Promise((resolve, reject) => {
            let body = '';
            
            req.on('data', (chunk) => {
                body += chunk.toString();
            });

            req.on('end', () => {
                try {
                    const data = body ? JSON.parse(body) : {};
                    resolve(data);
                } catch (error) {
                    reject(new Error('Invalid JSON in request body'));
                }
            });

            req.on('error', (error) => {
                reject(error);
            });
        });
    }

    /**
     * Extract path parameter from URL
     */
    extractPathParam(url, position) {
        const parts = url.split('/');
        return parts[position];
    }

    /**
     * Generate session token
     */
    generateSessionToken() {
        return 'token_' + Date.now() + '_' + Math.random().toString(36).substr(2, 16);
    }

    /**
     * Generate invite URL
     */
    getInviteUrl(req, inviteCode) {
        const protocol = req.headers['x-forwarded-proto'] || 'http';
        const host = req.headers.host;
        return `${protocol}://${host}/?invite=${inviteCode}`;
    }

    /**
     * Generate WebSocket URL
     */
    getWebSocketUrl(req) {
        const protocol = req.headers['x-forwarded-proto'] === 'https' ? 'wss' : 'ws';
        const host = req.headers.host;
        return `${protocol}://${host}/ws`;
    }

    /**
     * Send JSON response
     */
    sendJSON(res, statusCode, data) {
        res.writeHead(statusCode, {
            'Content-Type': 'application/json'
        });
        res.end(JSON.stringify(data));
    }

    /**
     * Send error response
     */
    sendError(res, statusCode, message) {
        this.sendJSON(res, statusCode, {
            success: false,
            error: message,
            timestamp: new Date()
        });
    }
}

module.exports = ApiRouter;